package com.xdcplus.web.service.device.impl;

import com.xdcplus.core.utils.BeanUtils;
import com.xdcplus.mom.utils.print.StringUtils;
import com.xdcplus.web.common.enums.device.BdOpeAndRegion;
import com.xdcplus.web.common.pojo.dto.device.DevicePerformanceFilterDTO;
import com.xdcplus.web.common.pojo.vo.device.DeviceFaultDetailVO;
import com.xdcplus.web.common.pojo.vo.device.DevicePerformanceVO;
import com.xdcplus.web.common.pojo.vo.device.DeviceStatusDurationVO;
import com.xdcplus.web.common.pojo.vo.device.ToolProduceVO;
import com.xdcplus.web.mapper.device.DevicePerformanceMapper;
import com.xdcplus.web.service.device.DevicePerformanceService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 设备OEE表服务实现类
 *
 * @author Richard.Li
 * @since 2024-06-19 09:11:05
 */
@Slf4j
@Service("DevicePerformanceService")
public class DevicePerformanceServiceImpl implements DevicePerformanceService {

    @Autowired
    private DevicePerformanceMapper devicePerformanceMapper;

    /**
     * 临时需求：获取设备异常单维修时长
     * @param devicePerformanceFilterDTO 设备性能分析过滤条件
     * @return
     */
    @Override
    public List<DevicePerformanceVO> queryDevicePerformanceData(DevicePerformanceFilterDTO devicePerformanceFilterDTO) {

        if (!StringUtils.isEmpty(devicePerformanceFilterDTO.getShiftCode()) && "A".equalsIgnoreCase(devicePerformanceFilterDTO.getShiftCode())) {
            devicePerformanceFilterDTO.setShiftCode("0");
        } else if (!StringUtils.isEmpty(devicePerformanceFilterDTO.getShiftCode()) && "B".equalsIgnoreCase(devicePerformanceFilterDTO.getShiftCode())) {
            devicePerformanceFilterDTO.setShiftCode("2");
        }

        List<String> regionCodeList = new ArrayList<>();
        devicePerformanceFilterDTO.getOpeCodeList().forEach(opeCode -> regionCodeList.add(String.valueOf(BdOpeAndRegion.getCodeByName(opeCode))));
        devicePerformanceFilterDTO.setRegionCodeList(regionCodeList);

        List<DeviceStatusDurationVO> deviceStatusDurationVOS = devicePerformanceMapper.queryDeviceStatusDurations(devicePerformanceFilterDTO);

        //查询产量
        List<ToolProduceVO> toolProduceVOS = devicePerformanceMapper.queryProdCount(devicePerformanceFilterDTO);

        Map<String, Long> theoryProductionMap = toolProduceVOS.stream().collect(
                Collectors.toMap(
                        ToolProduceVO::getToolCode,
                        v -> BigDecimal.valueOf(v.getTheoreticalCapacity()).divide(BigDecimal.valueOf(24), 0, RoundingMode.HALF_UP).longValue()
                )
        );

        /// 查询维修单信息


        List<DevicePerformanceVO> result = new ArrayList<>();
        for (DeviceStatusDurationVO deviceStatusDurationVO : deviceStatusDurationVOS) {
            DevicePerformanceVO devicePerformanceVO = new DevicePerformanceVO();
            devicePerformanceVO.setShiftDate(deviceStatusDurationVO.getShiftDate());
            devicePerformanceVO.setShiftCode(deviceStatusDurationVO.getShiftCode());
            devicePerformanceVO.setToolCode(deviceStatusDurationVO.getToolCode());
            devicePerformanceVO.setToolName(deviceStatusDurationVO.getToolName());
            devicePerformanceVO.setOpeName(deviceStatusDurationVO.getOpeName());
            Long ctValue = theoryProductionMap.getOrDefault(deviceStatusDurationVO.getToolCode(), 0L);
            devicePerformanceVO.setCt(String.valueOf(ctValue));
            devicePerformanceVO.setTheoryProduction(String.valueOf(ctValue * 12));

            /// 1.修正，取设备在班次时间范围内的对应的维修单的创建到验证时间的总时长
            /// 2. 取值是分钟，显示是小时，要转化
//            devicePerformanceVO.setRepairTime(deviceStatusDurationVO.getMaintainDuration());

            String startShiftDate = deviceStatusDurationVO.getShiftDate();
            String endShiftDate = deviceStatusDurationVO.getShiftDate();
            if ("0".equals(deviceStatusDurationVO.getShiftCode())) {
                startShiftDate += " 08:00:00";
                endShiftDate += " 20:00:00";
            }else if ("2".equals(deviceStatusDurationVO.getShiftCode())) {
                startShiftDate += " 20:00:00";
                endShiftDate = LocalDate.parse(endShiftDate,DateTimeFormatter.ofPattern("yyyy-MM-dd")).plusDays(1L)
                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 08:00:00";
            }else {
                startShiftDate += " 08:00:00";
                endShiftDate = LocalDate.parse(endShiftDate,DateTimeFormatter.ofPattern("yyyy-MM-dd")).plusDays(1L)
                        .format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 08:00:00";
            }

            devicePerformanceVO.setRepairTime(devicePerformanceMapper.queryRepairTimeByDevice(
                    devicePerformanceVO.getToolCode(),
                    startShiftDate,endShiftDate
            ));


            devicePerformanceVO.setActualProduction(deviceStatusDurationVO.getOutPut());

            devicePerformanceVO.setPerformanceEfficiency(String.valueOf(divide(devicePerformanceVO.getActualProduction(), devicePerformanceVO.getTheoryProduction(), 4)));

            Double totalDuration = Double.parseDouble(deviceStatusDurationVO.getDownDuration());
            devicePerformanceVO.setTimeEfficiency(String.valueOf(1-divide(String.valueOf(totalDuration), "720", 4)));

            devicePerformanceVO.setOee(String.valueOf(
                    new BigDecimal(devicePerformanceVO.getPerformanceEfficiency()).multiply(new BigDecimal(devicePerformanceVO.getTimeEfficiency()))
                            .setScale(4, RoundingMode.HALF_UP).doubleValue())
            );
            devicePerformanceVO.setTimeLost(String.valueOf(divide(String.valueOf(totalDuration), "60",2)));
            devicePerformanceVO.setLossProduction(String.valueOf(divide(String.valueOf(totalDuration * ctValue), "60", 0)));

            devicePerformanceVO.setMttr(String.valueOf(divide(String.valueOf(totalDuration), deviceStatusDurationVO.getOffCount(), 2)));
            devicePerformanceVO.setMtbf(String.valueOf(divide(String.valueOf(720 - totalDuration), deviceStatusDurationVO.getOffCount(), 2)));

            // 计算理论损失、实际产量和损失产量之间的差值
            double theoryProduction = Double.parseDouble(devicePerformanceVO.getTheoryProduction());
            double actualProduction = Double.parseDouble(devicePerformanceVO.getActualProduction());
            double lossProduction = Double.parseDouble(devicePerformanceVO.getLossProduction());

            // 计算其他损失，确保其不小于0
            double otherLoss = Math.max(0, theoryProduction - actualProduction - lossProduction);

            // 设置其他损失
            devicePerformanceVO.setOtherLoss(String.valueOf(otherLoss));

            result.add(devicePerformanceVO);
        }

        result.sort(Comparator.comparing(DevicePerformanceVO::getShiftDate).thenComparing(DevicePerformanceVO::getShiftCode).thenComparing(DevicePerformanceVO::getToolCode));

        return result;
    }

    @Override
    public List<DeviceFaultDetailVO> queryDeviceRepairDetail(DevicePerformanceFilterDTO devicePerformanceFilterDTO) {
        LocalDate endDate = LocalDate.parse(devicePerformanceFilterDTO.getEndDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        if (!StringUtils.isEmpty(devicePerformanceFilterDTO.getShiftCode()) && "A".equalsIgnoreCase(devicePerformanceFilterDTO.getShiftCode())) {
            devicePerformanceFilterDTO.setStartDate(devicePerformanceFilterDTO.getStartDate() + " 08:00:00");
            devicePerformanceFilterDTO.setEndDate(devicePerformanceFilterDTO.getEndDate() + " 20:00:00");
        } else if (!StringUtils.isEmpty(devicePerformanceFilterDTO.getShiftCode()) && "B".equalsIgnoreCase(devicePerformanceFilterDTO.getShiftCode())) {
            devicePerformanceFilterDTO.setStartDate(devicePerformanceFilterDTO.getStartDate() + " 20:00:00");
            endDate = endDate.plusDays(1);
            devicePerformanceFilterDTO.setEndDate(endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 08:00:00");
        } else {
            devicePerformanceFilterDTO.setStartDate(devicePerformanceFilterDTO.getStartDate() + " 08:00:00");
            endDate = endDate.plusDays(1);
            devicePerformanceFilterDTO.setEndDate(endDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")) + " 08:00:00");
        }
        List<String> regionCodeList = new ArrayList<>();
        devicePerformanceFilterDTO.getOpeCodeList().forEach(opeCode -> regionCodeList.add(String.valueOf(BdOpeAndRegion.getCodeByName(opeCode))));
        devicePerformanceFilterDTO.setRegionCodeList(regionCodeList);

        List<DeviceFaultDetailVO> deviceFaultDetailVOS = devicePerformanceMapper.queryOrderDetail(devicePerformanceFilterDTO);
        List<DeviceFaultDetailVO> result = new ArrayList<>();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        for (DeviceFaultDetailVO deviceFaultDetailVO : deviceFaultDetailVOS) {
            // 获取 faultTime 和 repairEndTime
            Date faultTime;
            Date repairEndTime;
            try {
                faultTime = sdf.parse(deviceFaultDetailVO.getRepairStartTime());
                repairEndTime = sdf.parse(deviceFaultDetailVO.getRepairEndTime());
            } catch (ParseException e) {
                log.error("日期格式转换异常", e);
                continue;
            }

            // 计算日期和班次信息
            List<Map<String, String>> dateShiftData = calculateDateShiftData(faultTime, repairEndTime);

            // 将计算结果设置到 deviceFaultDetailVO 中
            dateShiftData.forEach(data -> {
                DeviceFaultDetailVO detailVO = BeanUtils.copyProperties(deviceFaultDetailVO, DeviceFaultDetailVO.class);
                detailVO.setShiftDate(data.get("date"));
                detailVO.setShiftCode(data.get("shift"));
                result.add(detailVO);
            });

        }

        return result;
    }

    @Override
    public List<DeviceFaultDetailVO> queryDeviceFaultDetail(DevicePerformanceFilterDTO devicePerformanceFilterDTO) {
        if (!StringUtils.isEmpty(devicePerformanceFilterDTO.getShiftCode()) && "A".equalsIgnoreCase(devicePerformanceFilterDTO.getShiftCode())) {
            devicePerformanceFilterDTO.setShiftCode("0");
        } else if (!StringUtils.isEmpty(devicePerformanceFilterDTO.getShiftCode()) && "B".equalsIgnoreCase(devicePerformanceFilterDTO.getShiftCode())) {
            devicePerformanceFilterDTO.setShiftCode("2");
        }

        List<String> regionCodeList = new ArrayList<>();
        devicePerformanceFilterDTO.getOpeCodeList().forEach(opeCode -> regionCodeList.add(String.valueOf(BdOpeAndRegion.getCodeByName(opeCode))));
        devicePerformanceFilterDTO.setRegionCodeList(regionCodeList);

        return devicePerformanceMapper.queryDeviceFaultDetail(devicePerformanceFilterDTO);
    }

    private List<Map<String, String>> calculateDateShiftData(Date faultTime, Date repairEndTime) {
        List<Map<String, String>> dateShiftData = new ArrayList<>();

        Calendar startCal = Calendar.getInstance();
        startCal.setTime(faultTime);
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(repairEndTime);

        do {
            Map<String, String> data = new HashMap<>();
            data.put("date", getDate(startCal.getTime()));
            data.put("shift", getShift(startCal.getTime()));
            dateShiftData.add(data);
            startCal.add(Calendar.HOUR_OF_DAY, 12);
        } while (startCal.before(endCal));

        return dateShiftData;
    }

    // 获取某个时间的班次
    private String getShift(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        if (hour >= 8 && hour < 20) {
            return "白班";
        } else {
            return "夜班";
        }
    }

    // 获取某个时间的日期，如果时间早于8点，则返回前一天日期
    private String getDate(Date date) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);

        // 检查小时是否小于8
        if (cal.get(Calendar.HOUR_OF_DAY) < 8) {
            // 调整为前一天
            cal.add(Calendar.DAY_OF_YEAR, -1);
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(cal.getTime());
    }



    private static double divide(String dividend, String divisor, int scale) {
        // 检查除数是否为0
        if ("0".equals(divisor)) {
            return 0.0;
        }

        return new BigDecimal(dividend).divide(new BigDecimal(divisor), scale, RoundingMode.HALF_UP).doubleValue();
    }

}
